/*
 * ModUartAVRxx4.c
 *
 * Created: 23/03/2012 17:03:06
 *  Author: marionse
 */ 

#include <util/atomic.h>

#include "ModUart.h"
#include "ModRF.h"


/**
* \brief FONCTION PRIVEE DU MODULE
*/
static Int8U modUartToAscii( Int8U i_value );
static void modUartSendByte( Int8U i_binary_byte );
static Int8U modUartFromoAscii( Int8U i_value );

/**
* \brief fonction utilitaire qui retourne la valeur ASCII d'un nombre sur 4 bits
*
* \param[IN] entier a convertir compris entre 0x0 et 0xF inclus
*
* \return valeur ASCII
*/
static Int8U ModUartToAscii( Int8U i_value );

/**
* \brief fonction utilitaire qui retourne la sur 4 bits representer par un code ASCII
*
* \param[IN] code ASCII a convertir
*
* \return valeur comprise entre 00x et 0xF inclus
*/
static Int8U ModUartFromoAscii( Int8U i_value );


/**
* \brief CONSTANTE DU MODULE
*/
#define NB_MAX_MSG 5
#define MAX_RX_SIZE (sizeof(SFamMsg))

// ascii delimiter frame
#define STX 0x02U
#define ETX 0x03U


/**
* \brief VARIABLES PRIVEE DU MODULE
*/
static struct  
{
	// variable d'etat de la reception
	Boolean rx_state_in_progress;
	Int8U rx_counter;
	Int8U current_rx[MAX_RX_SIZE];
	
	// pile de reception de message uart
	Int8U nb_msg;
	TUartMsg msg[NB_MAX_MSG];
}mod_uart;

/**
* \brief fonction d'initialisation du module
*/
ERetCode ModUartInit( void )
{
	ERetCode lo_ret_code = E_RET_SUCCESS;
	
	/** initialise les variables privee */
	mod_uart.rx_state_in_progress = FALSE;
	mod_uart.rx_counter = 0;
	mod_uart.nb_msg = 0;
	
	/** configure l'uart1 a 38400bauds 8bits, 1stop no parity */
	/** incompatible avec la gestion de servomoteur qui bloque les interruption pendant 3ms */

	/** active le peripherique */
	PRR &= ~(1U << PRUSART1);
	UCSR1A |= (1U << TXC1);
	
	/** configure la vitesse */
	/** 38400 */
	UCSR1A &= ~(1U << U2X1);
	UBRR1 = 12U;
	/** async uart */
	/** data bites 8 */
	/** parity none */
	/** 1 bit stop */
	UCSR1C = ((1U<<2) | (1<<1));
	
	/** enable send & receive */
	/** active l'interruption de reception */
	UCSR1B |= ((1U<<3)|(1U<<4) | (1<<7));
	
	return lo_ret_code;
}

/**
* \brief fonction appelee a chaque passage dans la boucle main
*/
ERetCode ModUartTick( void )
{
	ERetCode lo_ret_code = E_RET_SUCCESS;
	

	return lo_ret_code;
}


/**
* \brief fonction utilitaire qui retourne la valeur ASCII d'un nombre sur 4 bits
*
* \param[IN] entier a convertir compris entre 0x0 et 0xF inclus
*
* \return valeur ASCII
*/
static Int8U modUartToAscii( Int8U i_value )
{
  if ( i_value < 0x0AU )
  {
    i_value += 0x30U;
  }
  else
  {
    i_value -= 0x0AU;
    i_value += 0x61U;
  }
  
  return i_value;
}

/**
* \brief fonction utilitaire qui retourne la sur 4 bits representer par un code ASCII
*
* \param[IN] code ASCII a convertir
*
* \return valeur comprise entre 00x et 0xF inclus
*/
static Int8U modUartFromoAscii( Int8U i_value )
{
  if( (i_value > 0x60U) && (i_value < 0x67U) )
  {
    i_value -= 0x61U;
    i_value += 0x0AU;
  }
  else if( (i_value > 0x40U) && (i_value < 0x47U) )
  {
    i_value -= 0x41U;
    i_value += 0x0AU;
  }
  else if( (i_value > 0x2FU) && (i_value < 0x3AU) )
  {
    i_value -= 0x30U;
  }
  else
  {
    // par defaut on met une valeur coherente
    i_value = 0U;
  }
  
  return i_value;
}

/**
* \brief fonction d'envoi d'un octet binaire en ascii sur l'uart
*/
static void modUartSendByte( Int8U i_binary_byte )
{
		// msb
		while ( !( UCSR1A & (1<<UDRE1)) )
			;
		UDR1 = modUartToAscii( (i_binary_byte>>4) );
			
		// lsb
		while ( !( UCSR1A & (1<<UDRE1)) )
			;
		UDR1 = modUartToAscii( (i_binary_byte&0x0F) );
}

/**
* \brief fonction d'envoi d'un message rf sur l'uart
*
* \param[IN] ip_rf_msg : message radio a envoyer sur l'uart
*/
ERetCode modUartSendMsg( TRFMsg *ip_rf_msg )
{
	ERetCode lo_ret_code = E_RET_SUCCESS;
	Int8U loop;
	
	/** l'envoi est vraiment basique */
	// efface le flag d'envoi
	UCSR1A |= (1<<TXC1);
	
	/** start frame */
	while ( !( UCSR1A & (1<<UDRE1)) )
		;
	UDR1 = STX;

	// lnk
	modUartSendByte( ip_rf_msg->em_lnk );
	
	// rssi
	modUartSendByte( ip_rf_msg->em_rssi );
	
	// src address
	modUartSendByte( ip_rf_msg->src_addr & 0xFF );
	modUartSendByte( ip_rf_msg->src_addr >> 8 );

	// fam_id
	modUartSendByte( ip_rf_msg->msg.family_id );
	
	// cmd_id
	modUartSendByte( ip_rf_msg->msg.cmd_id );
	
	// msg_len
	modUartSendByte( ip_rf_msg->msg.len );
	
	// msg
	for( loop=0; loop<ip_rf_msg->msg.len; loop++ )
	{
		modUartSendByte( ip_rf_msg->msg.payload[loop] );
	}

	/** end frame */
	while ( !( UCSR1A & (1<<UDRE1)) )
		;
	UDR1 = ETX;

	return lo_ret_code;
}

/**
* \brief fonction de recuperation d'un message uart
*        si le module retourne success, un message est present dans le buffer
*        si le buffer est NULL, alors le message est perdu
*
* \param[IN] op_buffer buffer dans lequel sera copier le message recu, si NULL le message est perdu
*/
ERetCode modUartGetMsg( TUartMsg *op_buffer )
{
	ERetCode lo_ret_code = E_RET_NO_MSG;
	
	if( 0 != mod_uart.nb_msg )
	{
		ATOMIC_BLOCK(ATOMIC_FORCEON)
		{
			Int8U loop;
			*op_buffer = mod_uart.msg[0];
			mod_uart.nb_msg -= 1;
			for( loop=0; loop<mod_uart.nb_msg; loop++ )
			{
				memmove( &mod_uart.msg[loop], &mod_uart.msg[loop+1], sizeof(TUartMsg) );
			}
		}
		
		lo_ret_code = E_RET_SUCCESS;
	}

	return lo_ret_code;
}



/**
* \brief fonction d'interruption de la reception uart
*/
ISR(USART1_RX_vect)
{
	Int8U l_value = UDR1;
	
	if( FALSE == mod_uart.rx_state_in_progress )
	{
		if( STX == l_value )
		{
			mod_uart.rx_state_in_progress = TRUE;
			mod_uart.rx_counter = 0;
		}
	}
	else
	{
		if( STX == l_value )
		{
			mod_uart.rx_counter = 0;
		}
		else if( ETX == l_value )
		{
			/** fin de reception, on transfert dans la pile d'attente */
			if( mod_uart.nb_msg < NB_MAX_MSG )
			{
				/** on doit empiler le message */
				mod_uart.msg[mod_uart.nb_msg].dest_addr = mod_uart.current_rx[0];
				mod_uart.msg[mod_uart.nb_msg].dest_addr |= (mod_uart.current_rx[1]<<8);
				mod_uart.msg[mod_uart.nb_msg].msg.family_id = mod_uart.current_rx[2];
				mod_uart.msg[mod_uart.nb_msg].msg.cmd_id = mod_uart.current_rx[3];
				mod_uart.msg[mod_uart.nb_msg].msg.len = mod_uart.current_rx[4];
				memcpy( mod_uart.msg[mod_uart.nb_msg].msg.payload, &mod_uart.current_rx[5], mod_uart.current_rx[4] );
				mod_uart.nb_msg += 1;				
			}
			
			/** attend un ouveau message */
			mod_uart.rx_state_in_progress  = FALSE;
		}
		else
		{
			l_value = modUartFromoAscii( l_value );
			if ( (mod_uart.rx_counter%2U) == 0U )
			{
				// il s'agit du msb
				mod_uart.current_rx[(mod_uart.rx_counter/2U)] = l_value << 4U;
			}
			else
			{
				// lsb
				mod_uart.current_rx[(mod_uart.rx_counter/2U)] += l_value;
			}
			mod_uart.rx_counter += 1U;
		}
	}
}